#include "log.hpp"
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <memory>
#include <fcntl.h>
#include <pthread.h>

class client
{
public:
    client(const string &serverIp, const uint16_t &serverPort)
        : _serverIp(serverIp), _serverPort(serverPort), _isrunning(false)
    {
        init();
    }
    ~client()
    {
        close(_fd);
    }
    void init()
    {
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            log(ERROR, "open socket fail!");
            cout << "error: " << strerror(errno) << endl;
            exit(-1);
        }
        log(NOTICE, "open socket success!");
    }

    struct threadData
    {
        sockaddr_in _server;
        socklen_t _len;
        client *_ptr;
    };

    static void *sendMsg(void *args)
    {
        threadData *td = static_cast<threadData *>(args);
        while (true)
        {
            cout << "请输入: ";
            string str;
            getline(cin, str);

            int n = sendto(td->_ptr->_fd, str.c_str(), str.size() + 1, 0, (const sockaddr *)&(td->_server), td->_len);
            if (n == -1)
            {
                log(WARNING, "sendto fail!");
            }
        }
    }

    static void *recvMsg(void *args)
    {
        threadData *td = static_cast<threadData *>(args);
        while (true)
        {
            char buffer[1024] = {0};
            struct sockaddr_in temp;
            socklen_t len = sizeof(temp);
            int n = recvfrom(td->_ptr->_fd, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&temp, &len);
            buffer[n] = '\0';
            //cout << buffer << endl;
            
            //重定向错误输出到云服务器1上，使得可以让输入与输出分离
            int fd=open("/dev/pts/3",O_WRONLY);
            dup2(fd,2);
            cerr << buffer << endl;
        }
    }

    void run()
    {
        _isrunning = true;
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(_serverIp.c_str());
        server.sin_port = htons(_serverPort);
        socklen_t len = sizeof(server);

        threadData td;
        td._len = len;
        td._server = server;
        td._ptr = this;
        // cout<<"debug: "<<_serverIp.c_str()<<" "<<_serverPort<<endl;

        pthread_create(&_senMsg, 0, sendMsg, (void *)&td);
        pthread_create(&_recvMsg, 0, recvMsg, (void *)&td);

        void *ret;
        pthread_join(_recvMsg, &ret);
        pthread_join(_senMsg, &ret);
    }

private:
    int _fd;
    string _serverIp;
    uint16_t _serverPort;
    bool _isrunning;
    pthread_t _recvMsg;
    pthread_t _senMsg;
};
